package io.easyspring.invitation.core.impl;

import io.easyspring.framework.common.exception.CommonException;
import io.easyspring.invitation.core.InvitationRepository;
import io.easyspring.invitation.core.properties.InvitationProperties;
import io.easyspring.invitation.core.properties.InvitationRedisKeyConstant;
import io.easyspring.invitation.core.support.EasyInvitation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 邀请信息存储器 -- redis 实现
 *
 * @author summer
 * @version 2.0.0-RELEASE
 * DateTime 2019-06-22 13:41
 */
@Slf4j
public class RedisInvitationRepository<T extends EasyInvitation> implements InvitationRepository<T> {

    /**
     * 注入 Redis 的模板
     */
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    /**
     * 注入邀请信息的配置
     */
    @Autowired
    private InvitationProperties invitationProperties;

    /**
     * 保存邀请信息的方法
     *
     * @param easyInvitation 邀请信息
     * @param expires 有效时长
     * @return T
     * Author summer
     * Version 2.0.0-RELEASE
     * DateTime 2019-06-22 13:42
     */
    @Override
    public T save(T easyInvitation, Long expires) {
        log.info("[邀请信息] 存储邀请信息到 Redis 中, easyInvitation: {}", easyInvitation);

        // 获取邀请信息的 key
        String key = buildInvitationKey(easyInvitation.getInviterId(),
                easyInvitation.getVerificationCode());

        // 重新获取过期时间
        expires = expires == null ? invitationProperties.getExpire() : expires;

        // 保存邀请信息到 redis 中
        redisTemplate.opsForValue()
                .set(key, easyInvitation, expires, TimeUnit.SECONDS);

        return easyInvitation;
    }

    /**
     * 删除邀请信息的方法
     *
     * @param inviterId 邀请者 id
     * @param verificationCode 识别码
     * @return int
     * Author summer
     * Version 2.0.0-RELEASE
     * DateTime 2019-06-22 13:47
     */
    @Override
    public int remove(Long inviterId, String verificationCode) {
        // 生成邀请信息的 key
        String key = buildInvitationKey(inviterId, verificationCode);

        // 执行删除操作
        Boolean delete = redisTemplate.delete(key);

        return (delete == null || !delete) ? 0 : 1;
    }

    /**
     * 获取邀请信息的方法
     *
     * @param inviterId 邀请者 id
     * @param verificationCode 识别码
     * @return T
     * Author summer
     * Version 2.0.0-RELEASE
     * DateTime 2019-06-22 13:47
     */
    @Override
    public T get(Long inviterId, String verificationCode) {
        // 生成邀请信息的 key
        String key = buildInvitationKey(inviterId, verificationCode);

        return (T) redisTemplate.opsForValue().get(key);
    }

    /**
     * 根据邀请者 id 获取其邀请信息集合的方法
     *
     * @param inviterId 邀请者 id
     * @return java.util.List<T>
     * Author summer
     * Version 2.0.0-RELEASE
     * DateTime 2019-06-22 13:48
     */
    @Override
    @SuppressWarnings("unchecked")
    public List<T> list(Long inviterId) {

        // 获取邀请者信息前缀的 key
        String keyPrefix = buildInvitationInviterKey(inviterId);
        // 获取当前邀请者下所有的 key
        Set<Object> keys = redisTemplate.keys(keyPrefix);
        // 如果返回的 key 为空, 则直接返回 null
        if (CollectionUtils.isEmpty(keys)) {
            return null;
        }

        List<Object> objectList = redisTemplate.opsForValue().multiGet(keys);
        // 如果查询出的结果为空, 则直接返回空
        if (CollectionUtils.isEmpty(objectList)) {
            return null;
        }

        return objectList.stream()
                .filter(Objects::nonNull)
                .map(invitation -> (T)invitation)
                .collect(Collectors.toList());
    }

    /**
     * 封装邀请信息的 key 的方法
     *
     * @param inviterId 邀请者 id
     * @param verificationCode 验证码
     * @return java.lang.String
     * Author summer
     * Version 2.0.0-RELEASE
     * DateTime 2019-06-22 14:05
     */
    private String buildInvitationKey(Long inviterId, String verificationCode) {

        if (inviterId == null || inviterId < 0 || StringUtils.isEmpty(verificationCode)) {
            throw new CommonException("封装邀请信息的 key 出错, inviterId: "
                    + inviterId + ", verificationCode: " + verificationCode);
        }
        // 执行 key 的格式化并返回结果
        return String.format(InvitationRedisKeyConstant.INVITATION_KEY_TEMPLATE,
                inviterId, verificationCode);
    }

    /**
     * 封装邀请者的邀请信息前缀的 key
     *
     * @param inviterId 邀请者 id
     * @return java.lang.String
     * Author summer
     * Version 2.0.0-RELEASE
     * DateTime 2019-06-22 14:15
     */
    private String buildInvitationInviterKey(Long inviterId) {
        // 如果邀请者 id 不合法
        if (inviterId == null || inviterId < 0) {
            // 直接抛出异常
            throw new CommonException("封装邀请信息的 key 出错, inviterId: "
                    + inviterId);
        }

        // 执行 key 的格式化并返回结果
        return String.format(InvitationRedisKeyConstant.INVITATION_INVITER_KEY_TEMPLATE, inviterId);
    }
}
